#include <iostream>
using namespace std;
//1、RAII
//2、像指针一样
//3、解决拷贝问题（不同的智能指针的解决方式不一样）

namespace rtx
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~auto_ptr()
		{
			cout << "~auto_ptr -> delete: " << _ptr << endl;
			delete _ptr;
		}
		auto_ptr(auto_ptr<T>& ptr)
			:_ptr(ptr._ptr)
		{
			ptr._ptr = nullptr;
		}

		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			if (this != &ap) // 防止自己赋值给自己
			{
				if (_ptr) // 防止释放空，delete空也行
				{
					cout << "operator= -> Delete:" << _ptr << endl;
					delete _ptr;
				}
				_ptr = ap._ptr;
				ap._ptr = nullptr;
			}
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	protected:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			cout << "~unique_ptr -> delete: " << _ptr << endl;
			delete _ptr;
		}
		unique_ptr(unique_ptr<T>& ptr) = delete;
		unique_ptr<T>& operator=(unique_ptr<T>& ptr) = delete;

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	protected:
		T* _ptr;
	};

	template<class T>
	struct Delete
	{
		void operator()(T* ptr)
		{
			cout << "delete:" << ptr << endl;
			delete ptr;
		}
	};

	template<class T, class D = Delete<T>>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			, _pCount(new int(1))
		{}

		void Release()
		{
			if (--(*_pCount) == 0) // 防止产生内存泄漏,和析构一样,写成一个函数
			{
				//delete _ptr;
				delete _pCount;

				//D del;
				//del(_ptr);
				D()(_ptr); // 对_ptr直接用匿名对象删掉
			}
		}
		~shared_ptr()
		{
			Release();
		}

		shared_ptr(const shared_ptr<T>& sp)
			: _ptr(sp._ptr)
			, _pCount(sp._pCount)
		{
			(*_pCount)++;
		}

		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			//if (this != &sp)
			if (_ptr != sp._ptr) // 防止自己给自己赋值,注意不能比较this,类似s1 = s2; 再来一次s1 = s2;
			{                    // 比较_pCount也行
				//if (--(*_pCount) == 0) // 防止产生内存泄漏,和析构一样,写成一个函数
				//{
				//	delete _ptr;
				//	delete _pCount;
				//}
				Release(); // 检查被赋值的对象，防止产生内存泄漏,和析构一样,写成一个函数

				_ptr = sp._ptr;
				_pCount = sp._pCount;
				(*_pCount)++;
			}
			return *this;
		}

		int use_count()
		{
			return *_pCount;
		}
		T* get() const
		{
			return _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	protected:
		T* _ptr;
		int* _pCount;// 引用计数,有多线程安全问题,学了linux再讲,不能用静态成员
	};

	template<class T> // 辅助型智能指针，配合解决shared_ptr循环引用问题
	class weak_ptr // 没有RAII,不管理资源
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}
		weak_ptr(const shared_ptr<T>& sp)
			:_ptr(sp.get())
		{}
		weak_ptr(const weak_ptr<T>& wp)
			:_ptr(wp._ptr)
		{}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	protected:
		T* _ptr;
	};
}